/*
 * Copyright 2008 Mark Davidson.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.doofer.test

import org.doofer.*
import com.documentum.fc.client.*
import com.documentum.fc.common.*
import com.documentum.com.*

/**
 * Tests for Doofer
 */
class AttribUtilTest extends DooferBaseTest {

    def KEY_SINGLE_BOOLEAN = 'r_immutable_flag'
    boolean VALUE_SINGLE_BOOLEAN = true
    def KEY_REPEATING_BOOLEAN = 'repeating_boolean'
    def VALUE_REPEATING_BOOLEAN = [true, false]

    def KEY_SINGLE_DOUBLE = 'r_full_content_size'
    double VALUE_SINGLE_DOUBLE = 100
    def KEY_REPEATING_DOUBLE = 'repeating_double'
    def VALUE_REPEATING_DOUBLE = [200, 300]

    def KEY_SINGLE_ID = 'i_chronicle_id'
    def VALUE_SINGLE_ID
    def KEY_REPEATING_ID = 'i_folder_id'
    def VALUE_REPEATING_ID

    def KEY_SINGLE_INTEGER = 'r_content_size'
    int VALUE_SINGLE_INTEGER = 400
    def KEY_REPEATING_INTEGER = 'repeating_integer'
    def VALUE_REPEATING_INTEGER = [500, 600]

    def KEY_SINGLE_STRING = 'object_name'
    def VALUE_SINGLE_STRING = 'Test Document'
    def KEY_REPEATING_STRING = 'authors'
    def VALUE_REPEATING_STRING = ['Ren', 'Stimpy']

    def KEY_SINGLE_TIME = 'r_creation_date'
    def VALUE_SINGLE_TIME
    def KEY_REPEATING_TIME = 'a_effective_date'
    def VALUE_REPEATING_TIME

    def object = null
    def au = new AttribUtil()

    void setUp() {
        super.setUp()

        VALUE_SINGLE_ID = clientX.getId('123456789')
        VALUE_SINGLE_TIME = new DfTime(new Date())
        VALUE_REPEATING_ID = [clientX.getId('123456789'), clientX.getId('987654321')]
        VALUE_REPEATING_TIME = [new DfTime(new Date()), new DfTime(new Date())]
    }

    /**
     * Constructs a mock typed object
     */
    def buildMockTypedObject() {
        def obj = new MockTypedObject()

        obj.add(new MockAttrib(name: KEY_SINGLE_BOOLEAN, type: IDfAttr.DM_BOOLEAN, isRepeating: false, value: VALUE_SINGLE_BOOLEAN))
        obj.add(new MockAttrib(name: KEY_SINGLE_DOUBLE, type: IDfAttr.DM_DOUBLE, isRepeating: false, value: VALUE_SINGLE_DOUBLE))
        obj.add(new MockAttrib(name: KEY_SINGLE_ID, type: IDfAttr.DM_ID, isRepeating: false, value: VALUE_SINGLE_ID))
        obj.add(new MockAttrib(name: KEY_SINGLE_INTEGER, type: IDfAttr.DM_INTEGER, isRepeating: false, value: VALUE_SINGLE_INTEGER))
        obj.add(new MockAttrib(name: KEY_SINGLE_STRING, type: IDfAttr.DM_STRING, isRepeating: false, value: VALUE_SINGLE_STRING))
        obj.add(new MockAttrib(name: KEY_SINGLE_TIME, type: IDfAttr.DM_TIME, isRepeating: false, value: VALUE_SINGLE_TIME))

        obj.add(new MockAttrib(name: KEY_REPEATING_BOOLEAN, type: IDfAttr.DM_BOOLEAN, isRepeating: true, value: VALUE_REPEATING_BOOLEAN))
        obj.add(new MockAttrib(name: KEY_REPEATING_DOUBLE, type: IDfAttr.DM_DOUBLE, isRepeating: true, value: VALUE_REPEATING_DOUBLE))
        obj.add(new MockAttrib(name: KEY_REPEATING_ID, type: IDfAttr.DM_ID, isRepeating: true, value: VALUE_REPEATING_ID))
        obj.add(new MockAttrib(name: KEY_REPEATING_INTEGER, type: IDfAttr.DM_INTEGER, isRepeating: true, value: VALUE_REPEATING_INTEGER))
        obj.add(new MockAttrib(name: KEY_REPEATING_STRING, type: IDfAttr.DM_STRING, isRepeating: true, value: VALUE_REPEATING_STRING))
        obj.add(new MockAttrib(name: KEY_REPEATING_TIME, type: IDfAttr.DM_TIME, isRepeating: true, value: VALUE_REPEATING_TIME))

        obj
    }

    /**
     * Constructs a mock typed object with default values
     */
    def buildDefaultMockTypedObject() {
        def obj = new MockTypedObject()

        obj.add(new MockAttrib(name: KEY_SINGLE_BOOLEAN, type: IDfAttr.DM_BOOLEAN, isRepeating: false, value: null))
        obj.add(new MockAttrib(name: KEY_SINGLE_DOUBLE, type: IDfAttr.DM_DOUBLE, isRepeating: false, value: null))
        obj.add(new MockAttrib(name: KEY_SINGLE_ID, type: IDfAttr.DM_ID, isRepeating: false, value: null))
        obj.add(new MockAttrib(name: KEY_SINGLE_INTEGER, type: IDfAttr.DM_INTEGER, isRepeating: false, value: null))
        obj.add(new MockAttrib(name: KEY_SINGLE_STRING, type: IDfAttr.DM_STRING, isRepeating: false, value: null))
        obj.add(new MockAttrib(name: KEY_SINGLE_TIME, type: IDfAttr.DM_TIME, isRepeating: false, value: null))

        obj.add(new MockAttrib(name: KEY_REPEATING_BOOLEAN, type: IDfAttr.DM_BOOLEAN, isRepeating: true, value: []))
        obj.add(new MockAttrib(name: KEY_REPEATING_DOUBLE, type: IDfAttr.DM_DOUBLE, isRepeating: true, value: []))
        obj.add(new MockAttrib(name: KEY_REPEATING_ID, type: IDfAttr.DM_ID, isRepeating: true, value: []))
        obj.add(new MockAttrib(name: KEY_REPEATING_INTEGER, type: IDfAttr.DM_INTEGER, isRepeating: true, value: []))
        obj.add(new MockAttrib(name: KEY_REPEATING_STRING, type: IDfAttr.DM_STRING, isRepeating: true, value: []))
        obj.add(new MockAttrib(name: KEY_REPEATING_TIME, type: IDfAttr.DM_TIME, isRepeating: true, value: []))

        obj
    }

    /**
     * Tests readAttribs() method
     */
    void testReadAttribs() {
        object = buildMockTypedObject()
        def values = null

        println "testing readAttribs()"
        values = au.readAttribs(object: object, attribNames: [KEY_SINGLE_BOOLEAN,
                                                              KEY_SINGLE_DOUBLE,
                                                              KEY_SINGLE_ID,
                                                              KEY_SINGLE_INTEGER,
                                                              KEY_SINGLE_STRING,
                                                              KEY_SINGLE_TIME,
                                                              KEY_REPEATING_BOOLEAN,
                                                              KEY_REPEATING_DOUBLE,
                                                              KEY_REPEATING_ID,
                                                              KEY_REPEATING_INTEGER,
                                                              KEY_REPEATING_STRING,
                                                              KEY_REPEATING_TIME])
        assert(values)
        assertEquals(12, values.size())
        assert(values."$KEY_SINGLE_BOOLEAN")
        assert(values."$KEY_SINGLE_DOUBLE")
        assert(values."$KEY_SINGLE_ID")
        assert(values."$KEY_SINGLE_INTEGER")
        assert(values."$KEY_SINGLE_STRING")
        assert(values."$KEY_SINGLE_TIME")
        assert(values."$KEY_REPEATING_BOOLEAN")
        assert(values."$KEY_REPEATING_DOUBLE")
        assert(values."$KEY_REPEATING_ID")
        assert(values."$KEY_REPEATING_INTEGER")
        assert(values."$KEY_REPEATING_STRING")
        assert(values."$KEY_REPEATING_TIME")
        inspectAttrib(value: values."$KEY_SINGLE_BOOLEAN", expectedValue: VALUE_SINGLE_BOOLEAN, expectedClass: Boolean.class)
        inspectAttrib(value: values."$KEY_SINGLE_DOUBLE", expectedValue: VALUE_SINGLE_DOUBLE, expectedClass: Double.class)
        inspectAttrib(value: values."$KEY_SINGLE_ID", expectedValue: VALUE_SINGLE_ID.id, expectedClass: String.class)
        inspectAttrib(value: values."$KEY_SINGLE_INTEGER", expectedValue: VALUE_SINGLE_INTEGER, expectedClass: Integer.class)
        inspectAttrib(value: values."$KEY_SINGLE_STRING", expectedValue: VALUE_SINGLE_STRING, expectedClass: String.class)
        inspectAttrib(value: values."$KEY_SINGLE_TIME", expectedValue: VALUE_SINGLE_TIME.date, expectedClass: Date.class)
        inspectAttrib(value: values."$KEY_REPEATING_BOOLEAN", expectedValue: VALUE_REPEATING_BOOLEAN, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_BOOLEAN.size())
        inspectAttrib(value: values."$KEY_REPEATING_DOUBLE", expectedValue: VALUE_REPEATING_DOUBLE, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_DOUBLE.size())
        inspectAttrib(value: values."$KEY_REPEATING_ID", expectedValue: VALUE_REPEATING_ID*.id, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_ID.size())
        inspectAttrib(value: values."$KEY_REPEATING_INTEGER", expectedValue: VALUE_REPEATING_INTEGER, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_INTEGER.size())
        inspectAttrib(value: values."$KEY_REPEATING_STRING", expectedValue: VALUE_REPEATING_STRING, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_STRING.size())
        inspectAttrib(value: values."$KEY_REPEATING_TIME", expectedValue: VALUE_REPEATING_TIME*.date, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_TIME.size())
    }

    /**
     * Tests readAttrib() method
     */
    void testReadAttrib() {
        object = buildMockTypedObject()
        def value = null

        println "testing readAttrib() - single boolean"
        value = au.readAttrib(object: object, attribName: KEY_SINGLE_BOOLEAN)
        inspectAttrib(value: value, expectedValue: VALUE_SINGLE_BOOLEAN, expectedClass: Boolean.class)

        println "testing readAttrib() - single double"
        value = au.readAttrib(object: object, attribName: KEY_SINGLE_DOUBLE)
        inspectAttrib(value: value, expectedValue: VALUE_SINGLE_DOUBLE, expectedClass: Double.class)

        println "testing readAttrib() - single id"
        value = au.readAttrib(object: object, attribName: KEY_SINGLE_ID)
        inspectAttrib(value: value, expectedValue: VALUE_SINGLE_ID.id, expectedClass: String.class)

        println "testing readAttrib() - single integer"
        value = au.readAttrib(object: object, attribName: KEY_SINGLE_INTEGER)
        inspectAttrib(value: value, expectedValue: VALUE_SINGLE_INTEGER, expectedClass: Integer.class)

        println "testing readAttrib() - single string"
        value = au.readAttrib(object: object, attribName: KEY_SINGLE_STRING)
        inspectAttrib(value: value, expectedValue: VALUE_SINGLE_STRING, expectedClass: String.class)

        println "testing readAttrib() - single time"
        value = au.readAttrib(object: object, attribName: KEY_SINGLE_TIME)
        inspectAttrib(value: value, expectedValue: VALUE_SINGLE_TIME.date, expectedClass: Date.class)

        println "testing readAttrib() - repeating boolean"
        value = au.readAttrib(object: object, attribName: KEY_REPEATING_BOOLEAN)
        inspectAttrib(value: value, expectedValue: VALUE_REPEATING_BOOLEAN, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_BOOLEAN.size())

        println "testing readAttrib() - repeating double"
        value = au.readAttrib(object: object, attribName: KEY_REPEATING_DOUBLE)
        inspectAttrib(value: value, expectedValue: VALUE_REPEATING_DOUBLE, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_DOUBLE.size())

        println "testing readAttrib() - repeating id"
        value = au.readAttrib(object: object, attribName: KEY_REPEATING_ID)
        inspectAttrib(value: value, expectedValue: VALUE_REPEATING_ID.id, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_ID.size())

        println "testing readAttrib() - repeating integer"
        value = au.readAttrib(object: object, attribName: KEY_REPEATING_INTEGER)
        inspectAttrib(value: value, expectedValue: VALUE_REPEATING_INTEGER, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_INTEGER.size())

        println "testing readAttrib() - repeating string"
        value = au.readAttrib(object: object, attribName: KEY_REPEATING_STRING)
        inspectAttrib(value: value, expectedValue: VALUE_REPEATING_STRING, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_STRING.size())

        println "testing readAttrib() - repeating time"
        value = au.readAttrib(object: object, attribName: KEY_REPEATING_TIME)
        inspectAttrib(value: value, expectedValue: VALUE_REPEATING_TIME.date, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_TIME.size())
    }

    void testWriteAttribs() {
        println "testing writeAttribs()"

        object = buildDefaultMockTypedObject()
        def attribs = []
        attribs << [attribName: KEY_SINGLE_BOOLEAN, attribValue: VALUE_SINGLE_BOOLEAN]
        attribs << [attribName: KEY_SINGLE_DOUBLE, attribValue: VALUE_SINGLE_DOUBLE]
        attribs << [attribName: KEY_SINGLE_ID, attribValue: VALUE_SINGLE_ID.id]
        attribs << [attribName: KEY_SINGLE_INTEGER, attribValue: VALUE_SINGLE_INTEGER]
        attribs << [attribName: KEY_SINGLE_STRING, attribValue: VALUE_SINGLE_STRING]
        attribs << [attribName: KEY_SINGLE_TIME, attribValue: VALUE_SINGLE_TIME.date]
        attribs << [attribName: KEY_REPEATING_BOOLEAN, attribValue: VALUE_REPEATING_BOOLEAN]
        attribs << [attribName: KEY_REPEATING_DOUBLE, attribValue: VALUE_REPEATING_DOUBLE]
        attribs << [attribName: KEY_REPEATING_ID, attribValue: VALUE_REPEATING_ID*.id]
        attribs << [attribName: KEY_REPEATING_INTEGER, attribValue: VALUE_REPEATING_INTEGER]
        attribs << [attribName: KEY_REPEATING_STRING, attribValue: VALUE_REPEATING_STRING]
        attribs << [attribName: KEY_REPEATING_TIME, attribValue: VALUE_REPEATING_TIME*.date]

        au.writeAttribs(object: object, attribs: attribs)

        inspectAttrib(value: object.getValue(KEY_SINGLE_BOOLEAN), expectedValue: VALUE_SINGLE_BOOLEAN, expectedClass: Boolean.class)
        inspectAttrib(value: object.getValue(KEY_SINGLE_DOUBLE), expectedValue: VALUE_SINGLE_DOUBLE, expectedClass: Double.class)
        inspectAttrib(value: object.getValue(KEY_SINGLE_ID).id, expectedValue: VALUE_SINGLE_ID.id, expectedClass: String.class)
        inspectAttrib(value: object.getValue(KEY_SINGLE_INTEGER), expectedValue: VALUE_SINGLE_INTEGER, expectedClass: Integer.class)
        inspectAttrib(value: object.getValue(KEY_SINGLE_STRING), expectedValue: VALUE_SINGLE_STRING, expectedClass: String.class)
        inspectAttrib(value: object.getValue(KEY_SINGLE_TIME).date, expectedValue: VALUE_SINGLE_TIME.date, expectedClass: Date.class)
        inspectAttrib(value: object.getValue(KEY_REPEATING_BOOLEAN), expectedValue: VALUE_REPEATING_BOOLEAN, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_BOOLEAN.size())
        inspectAttrib(value: object.getValue(KEY_REPEATING_DOUBLE), expectedValue: VALUE_REPEATING_DOUBLE, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_DOUBLE.size())
        inspectAttrib(value: object.getValue(KEY_REPEATING_ID).id, expectedValue: VALUE_REPEATING_ID.id, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_ID.size())
        inspectAttrib(value: object.getValue(KEY_REPEATING_INTEGER), expectedValue: VALUE_REPEATING_INTEGER, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_INTEGER.size())
        inspectAttrib(value: object.getValue(KEY_REPEATING_STRING), expectedValue: VALUE_REPEATING_STRING, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_STRING.size())
        inspectAttrib(value: object.getValue(KEY_REPEATING_TIME).date, expectedValue: VALUE_REPEATING_TIME.date, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_TIME.size())
    }

    /**
     * Tests writeAttrib() method
     */
    void testWriteAttrib() {
        object = buildDefaultMockTypedObject()

        println "testing writeAttrib() - single boolean"
        au.writeAttrib(object: object, attribName: KEY_SINGLE_BOOLEAN, attribValue: VALUE_SINGLE_BOOLEAN)
        inspectAttrib(value: object.getValue(KEY_SINGLE_BOOLEAN), expectedValue: VALUE_SINGLE_BOOLEAN, expectedClass: Boolean.class)

        println "testing writeAttrib() - single double"
        au.writeAttrib(object: object, attribName: KEY_SINGLE_DOUBLE, attribValue: VALUE_SINGLE_DOUBLE)
        inspectAttrib(value: object.getValue(KEY_SINGLE_DOUBLE), expectedValue: VALUE_SINGLE_DOUBLE, expectedClass: Double.class)

        println "testing writeAttrib() - single id"
        au.writeAttrib(object: object, attribName: KEY_SINGLE_ID, attribValue: VALUE_SINGLE_ID.id)
        inspectAttrib(value: object.getValue(KEY_SINGLE_ID).id, expectedValue: VALUE_SINGLE_ID.id, expectedClass: String.class)

        println "testing writeAttrib() - single integer"
        au.writeAttrib(object: object, attribName: KEY_SINGLE_INTEGER, attribValue: VALUE_SINGLE_INTEGER)
        inspectAttrib(value: object.getValue(KEY_SINGLE_INTEGER), expectedValue: VALUE_SINGLE_INTEGER, expectedClass: Integer.class)

        println "testing writeAttrib() - single string"
        au.writeAttrib(object: object, attribName: KEY_SINGLE_STRING, attribValue: VALUE_SINGLE_STRING)
        inspectAttrib(value: object.getValue(KEY_SINGLE_STRING), expectedValue: VALUE_SINGLE_STRING, expectedClass: String.class)

        println "testing writeAttrib() - single time"
        au.writeAttrib(object: object, attribName: KEY_SINGLE_TIME, attribValue: VALUE_SINGLE_TIME.date)
        inspectAttrib(value: object.getValue(KEY_SINGLE_TIME).date, expectedValue: VALUE_SINGLE_TIME.date, expectedClass: Date.class)

        println "testing writeAttrib() - repeating boolean"
        au.writeAttrib(object: object, attribName: KEY_REPEATING_BOOLEAN, attribValue: VALUE_REPEATING_BOOLEAN)
        inspectAttrib(value: object.getValue(KEY_REPEATING_BOOLEAN), expectedValue: VALUE_REPEATING_BOOLEAN, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_BOOLEAN.size())

        println "testing writeAttrib() - repeating double"
        au.writeAttrib(object: object, attribName: KEY_REPEATING_DOUBLE, attribValue: VALUE_REPEATING_DOUBLE)
        inspectAttrib(value: object.getValue(KEY_REPEATING_DOUBLE), expectedValue: VALUE_REPEATING_DOUBLE, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_DOUBLE.size())

        println "testing writeAttrib() - repeating id"
        au.writeAttrib(object: object, attribName: KEY_REPEATING_ID, attribValue: VALUE_REPEATING_ID*.id)
        inspectAttrib(value: object.getValue(KEY_REPEATING_ID).id, expectedValue: VALUE_REPEATING_ID.id, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_ID.size())

        println "testing writeAttrib() - repeating integer"
        au.writeAttrib(object: object, attribName: KEY_REPEATING_INTEGER, attribValue: VALUE_REPEATING_INTEGER)
        inspectAttrib(value: object.getValue(KEY_REPEATING_INTEGER), expectedValue: VALUE_REPEATING_INTEGER, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_INTEGER.size())

        println "testing writeAttrib() - repeating string"
        au.writeAttrib(object: object, attribName: KEY_REPEATING_STRING, attribValue: VALUE_REPEATING_STRING)
        inspectAttrib(value: object.getValue(KEY_REPEATING_STRING), expectedValue: VALUE_REPEATING_STRING, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_STRING.size())

        println "testing writeAttrib() - repeating time"
        au.writeAttrib(object: object, attribName: KEY_REPEATING_TIME, attribValue: VALUE_REPEATING_TIME*.date)
        inspectAttrib(value: object.getValue(KEY_REPEATING_TIME).date, expectedValue: VALUE_REPEATING_TIME.date, expectedClass: ArrayList.class, expectedSize: VALUE_REPEATING_TIME.size())
    }

    /**
     * Performs checks on typed objects
     */
    void inspectAttrib(Map params) {
        def value = params.value
        def expectedValue = params.expectedValue
        def expectedClass = params.expectedClass
        def expectedSize = params.expectedSize

        assert(value)
        assertEquals(expectedClass, value.getClass())
        if(value instanceof List) {
            assertEquals(expectedSize, value.size())
            expectedValue.eachWithIndex { val, index ->
                assertEquals(val, value[index])
            }
        } else {
            assertEquals(expectedValue, value)
        }
    }
}